#if defined(_MSC_VER)
#pragma once
#endif

#ifndef LM_CORE_LIGHT_H
#define LM_CORE_LIGHT_H

#include "lm.h"
#include "ray.h"
#include "spectrum.h"

struct VisibilityTester {
	Ray r;
	void SetSegment(const Point3 &ps, const Point3 &pe) {
		r = Ray(ps, pe-ps, RAYEPSILON, 1-RAYEPSILON);
	}
	void SetRay(const Point3 &p, const Vector3 &w) {
		r = Ray(p, w, RAYEPSILON);
	}
	bool Unoccluded(const Scene *scene) const;
	Spectrum Transmittance(const Scene *scene) const;
};

class Light {
public:
	Light(const Transform *l2w, const Transform *w2l, int ns = 1) : lightToWorld(l2w), worldToLight(w2l), nSamples(max(ns, 1)) { }
	~Light() { }
	virtual bool IsDeltaLight() const = 0;
	virtual Spectrum Power(const Scene *) const = 0;
	virtual Spectrum Sample_L(const Point3 &p, Vector3 *wi, VisibilityTester *vis) const = 0;
	virtual Spectrum Sample_L(const Point3 &p, const Point2 &sample, Vector3 *wi, float *pdf, VisibilityTester *vis) const = 0;
	virtual float Pdf(const Point3 &p, const Vector3 &wi) const = 0;
	virtual Spectrum Sample_L(const Point3 &p, const Normal &n, const Point2 &sample, Vector3 *wi, float *pdf, VisibilityTester *vis) const {
		return Sample_L(p, sample, wi, pdf, vis);
	}
	virtual float Pdf(const Point3 &p, const Normal &n, const Vector3 &wi) const {
		return Pdf(p, wi);
	}
	virtual Spectrum Sample_L(const Scene *scene, const Point2 &lightsample, const Point2 &dirsample, Ray *ray, float *pdf) const = 0;
	// public data
	int nSamples;
protected:
	const Transform *lightToWorld, *worldToLight;
};

#endif	// LM_CORE_LIGHT_H